﻿namespace Refract.Event
{
    using System;
    using System.ComponentModel.Composition;

    using Refract.Composition;

    /// <summary>
    /// A leak safe reference to an event.  
    /// </summary>
    /// <remarks>To be used with Notificaton Subscription</remarks>
    /// <typeparam name="TParam">The type of the param.</typeparam>
    public class Notification<TParam>
    {
        #region Fields

        private WeakReferenceToDelegate<EventArgs<TParam>> _eventReference = new WeakReferenceToDelegate<EventArgs<TParam>>();

        #endregion Fields

        #region Constructors

        public Notification(string name)
        {
            Container.Current.ComposeExportedValue(QualifiedName(name), this);
        }

        #endregion Constructors

        #region Methods

        /// <summary>
        /// Publishes the  notification to all subscribers.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="param">The param.</param>
        public void Publish(object source, TParam param)
        {
            _eventReference.FireEvent(source, new EventArgs<TParam>(param));
        }

        /// <summary>
        /// Returns a qualified notification name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        internal static string QualifiedName(string name)
        {
            return typeof(Notification).FullName + "." + name;
        }

        /// <summary>
        /// Subscribes the specified handler.
        /// </summary>
        /// <remarks>
        /// This method should only be invoked by a NoficationSubscription object to ensure that a strong reference is maintained
        /// to the delegate, otherwise the delegate will be removed by the garbage collector even if the delegate's source is alive
        /// </remarks> 
        /// <param name="handler">The handler.</param>
        internal void Subscribe(EventHandler<EventArgs<TParam>> handler)
        {
            _eventReference.Event += handler;
        }

        #endregion Methods
    }

    /// <summary>
    /// A leak safe reference to an event.  
    /// </summary>
    public class Notification : Notification<object>
    {
        #region Constructors

        public Notification(string name)
            : base(name)
        {
        }

        #endregion Constructors
    }
}